package com.zhg.shortlink.generator;


import com.zhg.shortlink.config.ShortCodeConfig;
import com.zhg.shortlink.util.Base62Util;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.time.Instant;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 分布式短码生成器
 * 基于雪花算法，利用JDK21的虚拟线程优化
 * 支持动态配置短链长度
 *  @author 朱洪刚
 *  @version 1.0
 *  @data 2025/10/21 14:47
 */
@Slf4j
@Component
public class ShortCodeGenerator {

    // 时间戳位数
    private static final long TIMESTAMP_BITS = 41L;
    // 机器ID位数
    private static final long MACHINE_ID_BITS = 10L;
    // 序列号位数
    private static final long SEQUENCE_BITS = 12L;

    // 最大值
    private static final long MAX_MACHINE_ID = (1L << MACHINE_ID_BITS) - 1;
    private static final long MAX_SEQUENCE = (1L << SEQUENCE_BITS) - 1;

    // 位移量
    private static final long MACHINE_ID_SHIFT = SEQUENCE_BITS;
    private static final long TIMESTAMP_SHIFT = SEQUENCE_BITS + MACHINE_ID_BITS;

    // 起始时间戳 (2024-01-01 00:00:00 UTC)
    private static final long START_TIMESTAMP = 1704067200000L;

    @Value("${shortlink.machine-id:1}")
    private long machineId;

    private final ShortCodeConfig shortCodeConfig;
    private final AtomicLong sequence = new AtomicLong(0L);
    private volatile long lastTimestamp = -1L;
    private final ReentrantLock lock = new ReentrantLock();

    // 缓存最大值，避免重复计算
    private volatile long cachedMaxValue = -1L;
    private volatile int cachedLength = -1;

    /**
     * 构造函数注入配置
     */
    public ShortCodeGenerator(ShortCodeConfig shortCodeConfig) {
        this.shortCodeConfig = shortCodeConfig;

        // 验证机器ID范围
        if (machineId < 0 || machineId > MAX_MACHINE_ID) {
            throw new IllegalArgumentException(
                    String.format("机器ID必须在0-%d之间，当前值: %d", MAX_MACHINE_ID, machineId));
        }

        log.info("短码生成器初始化完成 - 机器ID: {}, 配置长度: {}",
                machineId, shortCodeConfig.getLength());
    }

    /**
     * 生成唯一ID (利用JDK21的性能优化)
     */
    public long generateId() {
        lock.lock();
        try {
            long timestamp = getCurrentTimestamp();

            // 时钟回拨检查
            if (timestamp < lastTimestamp) {
                long offset = lastTimestamp - timestamp;
                if (offset <= 5) {
                    // 小幅回拨，等待追上
                    try {
                        Thread.sleep(offset << 1);
                        timestamp = getCurrentTimestamp();
                        if (timestamp < lastTimestamp) {
                            throw new RuntimeException("时钟回拨异常，拒绝生成ID");
                        }
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                        throw new RuntimeException("等待时钟同步被中断", e);
                    }
                } else {
                    throw new RuntimeException(
                            String.format("时钟回拨异常，回拨时间: %dms", offset));
                }
            }

            // 同一毫秒内
            if (timestamp == lastTimestamp) {
                long seq = sequence.incrementAndGet() & MAX_SEQUENCE;
                if (seq == 0) {
                    // 序列号用完，等待下一毫秒
                    timestamp = waitNextMillis(timestamp);
                    sequence.set(0L);
                }
            } else {
                // 新的毫秒，重置序列号
                sequence.set(0L);
            }

            lastTimestamp = timestamp;

            // 组装ID
            long id = ((timestamp - START_TIMESTAMP) << TIMESTAMP_SHIFT)
                    | (machineId << MACHINE_ID_SHIFT)
                    | sequence.get();

            // 确保ID不超过指定长度Base62编码的最大值
            long maxValue = getMaxValueForCurrentLength();
            return Math.abs(id) % maxValue;
        } finally {
            lock.unlock();
        }
    }

    /**
     * 生成短码 - 支持动态长度配置
     */
    public String generateShortCode() {
        long id = generateId();
        int targetLength = shortCodeConfig.getLength();

        // 使用配置的长度生成短码
        String shortCode = Base62Util.encodeWithMinLength(id, targetLength);

        // 确保不超过配置的长度
        if (shortCode.length() > targetLength) {
            shortCode = shortCode.substring(0, targetLength);
            log.debug("短码长度超限，已截取到{}位: {}", targetLength, shortCode);
        }

        return shortCode;
    }

    /**
     * 批量生成短码 (利用JDK21的虚拟线程)
     */
    public String[] generateBatchShortCodes(int count) {
        if (count <= 0) {
            throw new IllegalArgumentException("批量生成数量必须大于0");
        }

        if (count > 10000) {
            log.warn("批量生成数量较大: {}, 建议分批处理", count);
        }

        return java.util.stream.IntStream.range(0, count)
                .parallel()
                .mapToObj(i -> generateShortCode())
                .toArray(String[]::new);
    }

    /**
     * 获取当前配置长度对应的最大值（带缓存优化）
     */
    private long getMaxValueForCurrentLength() {
        int currentLength = shortCodeConfig.getLength();

        // 如果长度变化了，重新计算最大值
        if (currentLength != cachedLength) {
            synchronized (this) {
                if (currentLength != cachedLength) {
                    cachedMaxValue = Base62Util.getMaxValue(currentLength);
                    cachedLength = currentLength;
                    log.debug("更新缓存的最大值: length={}, maxValue={}",
                            currentLength, cachedMaxValue);
                }
            }
        }

        return cachedMaxValue;
    }

    /**
     * 获取当前时间戳
     */
    private long getCurrentTimestamp() {
        return Instant.now().toEpochMilli();
    }

    /**
     * 等待下一毫秒
     */
    private long waitNextMillis(long lastTimestamp) {
        long timestamp = getCurrentTimestamp();
        while (timestamp <= lastTimestamp) {
            Thread.onSpinWait(); // JDK21优化的自旋等待
            timestamp = getCurrentTimestamp();
        }
        return timestamp;
    }

    /**
     * 获取生成器状态信息（用于监控）
     */
    public GeneratorStatus getStatus() {
        return new GeneratorStatus(
                machineId,
                shortCodeConfig.getLength(),
                lastTimestamp,
                sequence.get(),
                getMaxValueForCurrentLength()
        );
    }

    /**
     * 生成器状态信息
     */
    public static class GeneratorStatus {
        private final long machineId;
        private final int configuredLength;
        private final long lastTimestamp;
        private final long currentSequence;
        private final long maxValue;

        public GeneratorStatus(long machineId, int configuredLength,
                               long lastTimestamp, long currentSequence, long maxValue) {
            this.machineId = machineId;
            this.configuredLength = configuredLength;
            this.lastTimestamp = lastTimestamp;
            this.currentSequence = currentSequence;
            this.maxValue = maxValue;
        }

        // Getters
        public long getMachineId() { return machineId; }
        public int getConfiguredLength() { return configuredLength; }
        public long getLastTimestamp() { return lastTimestamp; }
        public long getCurrentSequence() { return currentSequence; }
        public long getMaxValue() { return maxValue; }

        @Override
        public String toString() {
            return String.format(
                    "GeneratorStatus{machineId=%d, length=%d, lastTimestamp=%d, sequence=%d, maxValue=%d}",
                    machineId, configuredLength, lastTimestamp, currentSequence, maxValue
            );
        }
    }
}
